<template>
	<div class="ui-image" :title="alt">
		<img ref="imgElement" :src="status == 'success' ? src : null" class="ui-image_main" :style="imgStyle" />
		<template v-if="loadingProcess">
			<div v-show="status == 'loading'" class="ui-image_loading">
				<slot name="loading">
					Loading
				</slot>
			</div>
			<div v-show="status == 'error'" class="ui-image_error">
				<slot name="error">
					Error
				</slot>
			</div>
		</template>
	</div>
</template>

<script setup>
	
	import { defineComponent, ref, watch, computed, onMounted } from 'vue';
	import { findNearestScrollElement } from '@/utils/dom';

	const props = defineProps({
		src: String,
		alt: String,
		lazy: Boolean,
		fit: String,
		position: String,
		loadingProcess: {
			type: Boolean,
			default: true
		}
	})
	
	const emits = defineEmits(['load', 'success', 'error']);
	
	const status = ref();

	const imgElement = ref();
	
	let lazyObserver = null;
	
	const imgStyle = computed(() => {
		const sty = {};
		if (props.position) {
			sty.objectPosition = props.position;
			sty.objectFit = ['contain', 'none', 'scale-down'].includes(props.fit) ? props.fit : 'scale-down';
		} else {
			sty.objectFit = props.fit;
		}
		return sty;
	})
	
	onMounted(() => {
		watch(() => props.src, (newVal) => {
			status.value = null;
			if (newVal) {
				lazyObserver?.disconnect();
				if (props.lazy && IntersectionObserver) {
					lazyLoad(); 
				} else {
					immeLoad();
				}
			}
		}, {
			immediate: true
		})
	})
	
	function immeLoad() {
		emits('load');
		status.value = 'loading';
		const img = new Image();
		img.addEventListener('load', (e) => {
			status.value = 'success';
			emits('success', e);
		});
		img.addEventListener('error', (e) => {
			status.value = 'error';
			emits('error', e);
		});
		img.src = props.src;
	}
	
	function lazyLoad() {
		lazyObserver = new IntersectionObserver((entries, observer) => {
			if (entries[0].isIntersecting) {
				immeLoad();
				observer.disconnect();
			}
		}, {
			root: findNearestScrollElement(imgElement.value),
			rootMargin: '10px',
			threshold: [0]
		})
		lazyObserver.observe(imgElement.value)
	}
	
</script>

<style lang="scss" scoped>
	
	.ui-image {
		position: relative;
		display: inline-block;
		overflow: hidden;
	}
	
	.ui-image_main {
		display: block;
		width: 100%;
		height: 100%;
		border: none;
		&[src=""], &:not([src]) {
			opacity:0;
			width: 0;
			height: 0;
		}
	}
	
	.ui-image_loading, .ui-image_error {
		display: flex;
		width: 100%;
		height: 100%;
		align-items: center;
		justify-content: center;
		filter: drop-shadow(0 0 1px #ffffff);
		font-weight: bold;
	}
	
</style>